#include "plst.h"
#include "ui_mainwindow.h"
#include <QtGui>
#include <QFileDialog>
#include <QtDebug>
#include <taglib/tbytevector.h>//ByteVector
#include <taglib/mpegfile.h>//mp3 file
#include <taglib/oggfile.h> //ogg
#include <taglib/flacfile.h>
#include <taglib/flacpicture.h>
#include <taglib/aifffile.h>
#include <taglib/wavfile.h>

#include <taglib/id3v2tag.h>//tag
#include <taglib/id3v2frame.h>//frame
#include <taglib/attachedpictureframe.h>
#include <taglib/tstring.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <stdlib.h>

//TODO ADD SUPPORT ALL TAGS
using namespace std ;
using namespace TagLib::ID3v2 ;

pl_tag id3v2_to_pltag(TagLib::ID3v2::Tag *tg);
char *tstring2char(TagLib::String str);
void *xmalloc(size_t size);
QString char2qs(TagLib::String str);

const char* nms[FIELDS_NUM] = {"Artist Name", "Track Title", "Album Title", "Date", "Genre", "Track Number", "Comment"};
void plst::tgs_wgt_init(void)
{
	qDebug("plst:: tgs_wgt_init");
    if (tgs_wgt == NULL)
    {
        tgs_wgt = new QTableWidget(FIELDS_NUM, 2);
        QStringList lst;
        lst << "Name" << "Value";
        tgs_wgt->setHorizontalHeaderLabels(lst);
        for (int i = 0; i < FIELDS_NUM; i++)
        {
            QTableWidgetItem *pitem = new QTableWidgetItem();
            QString txt = nms[i];
            pitem->setText(txt);
            tgs_wgt->setItem(i, 0, pitem);
        }
    }
    if (!this->currentItem())
        return;
    qDebug("Dimension of vector == %d", tgs_lst.size());
    qDebug("current row == %d", this->currentRow());
    pl_tag tg = tgs_lst[this->currentRow()];
    for (int i = 0; i < tgs_wgt->rowCount(); i++)
    {
        QTableWidgetItem *pitem = new QTableWidgetItem();
        QString txt;
        switch (i)
        {
            case 0: txt = tg.artist;
                    break;
            case 1: txt = tg.title;
                    break;
            case 2: txt = tg.album;
                    break;
            case 3: txt.setNum(tg.year);
                    break;
            case 4: txt = tg.genre;
                    break;
            case 5: txt.setNum(tg.trackno);
                    break;
            case 6: txt = tg.comment;
        }
        pitem->setText(txt);
        tgs_wgt->setItem(i, 1, pitem);
    }
    tgs_wgt->show();
    qDebug("plst:: tgs_wgt_init end");
}

plst::~plst()
{
	qDebug("plst:: destructor");
    tgs_wgt->close();
    if (tgs_wgt)
        delete tgs_wgt;
    if (cover_image)
        delete cover_image;
    if (cover_view)
        delete cover_view;
    if (cover_scene)
        delete cover_scene;
    qDebug("plst:: destructor end");

}
void plst::cover_init(void)
{
    cover_view = NULL;
    cover_image = NULL;
    cover_scene = NULL;
}

plst::plst(QWidget *widget):QListWidget(widget)
{
	qDebug("plst:: constructor");
    this->clear();
    this->setSelectionMode(QAbstractItemView::SingleSelection);
    this->setViewMode(QListView::ListMode);
    this->setDragEnabled(true);
    this->viewport()->setAcceptDrops(true);
    this->setDropIndicatorShown(true);
    this->setDragDropMode(QAbstractItemView::InternalMove);
    this->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    this->setMinimumSize(628, 191);
    this->setMaximumSize(16777215, 16777215);
    tgs_wgt = NULL;
    cover_init();
    tgs_wgt_init();
    qDebug("plst:: constructor end");
}

char * plst::qs2char(QString str) //non-copy fast-hack
{
	qDebug("plst:: qs2char");
    char *n_ptr = (char*) xmalloc(sizeof(char)); n_ptr[0] = 0;
    if (str.isNull()){qDebug("return \\0 because str is null");
        return n_ptr;}
    if (str.isEmpty()){qDebug("return \\0 because str is Empty");
        return n_ptr;}
    if (str.toLocal8Bit().isEmpty() || str.toLocal8Bit().isNull())
    {qDebug("return \\0 because str is or is NULL");
            return n_ptr;}

    //bs = str.toUtf8();
    //bs = str.toLocal8Bit();
    //bs = str.toLatin1();
    bs = str.toLocal8Bit();
    qDebug("plst:: qs2char end");
    return bs.data();
}//*/
QString plst::get_file_name(void)
{
	qDebug("plst:: get_file_name");
    if (this->count() == 0)
        return NULL;
    if (!this->currentItem())
        this->setCurrentRow(0);
    qDebug("plst:: get_file_name end");
    return get_file_byid(this->currentRow());
}

QString plst::get_file_byid(int id)
{
	qDebug("plst:: get_file_byid");
    if ((id < 0)||(id >= this->count()))
        return NULL;
    this->setCurrentRow(id);
    tgs_wgt_init();
    TagLib::MPEG::File mp3file(qs2char(tgs_lst[id].fname));
  //  Tag *mp3tag = mp3file.ID3v2Tag();
    Tag *mp3tag = NULL;
    if (mp3file.isValid())
        mp3tag = mp3file.ID3v2Tag();
    if (mp3tag)
    {
        FrameList fmp3_list = mp3tag->frameListMap()["APIC"];
        if (!fmp3_list.isEmpty())
        {
            for (FrameList::ConstIterator i = fmp3_list.begin(); i != fmp3_list.end();i++)
            {
                QFile::remove("/tmp/cover.jpg");
                AttachedPictureFrame *frm = static_cast<AttachedPictureFrame *> (*i);
                FILE *fout = fopen("/tmp/cover.jpg", "wb");
                fwrite(frm->picture().data(), frm->picture().size(), 1, fout);
                fclose(fout);
                QPixmap mp;
                mp.load("/tmp/cover.jpg");
                if (!cover_scene)
                    cover_scene = new QGraphicsScene;
                if (!cover_view)
                    cover_view = new QGraphicsView(cover_scene);
                cover_scene->addPixmap(mp);
                cover_view->show();
            }
        }
    }
    qDebug("plst:: get_file_byid end");
    return tgs_lst[id].fname;
}


//-----------------ADDITION PROCEDURES---------------------------------------------


void plst::delete_selected(void)
{
	qDebug("plst:: delete_selected");
    qDebug("plst:: delete_selected end");
    // will be developed later
}




void plst::add_fileqs(QString fname)
{
	qDebug("plst:: add_fileqs");
    QListWidgetItem *item = new QListWidgetItem(fname, this);
    item->setFlags(Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsDragEnabled);
    //if ()
    TagLib::MPEG::File mp3file(qs2char(fname));
    Tag *mp3tag = NULL;
    if (mp3file.isValid())
        mp3tag = mp3file.ID3v2Tag();
    pl_tag tg  = {0, 0, "", "", "", "", "", ""};
    if (mp3tag)
        tg = id3v2_to_pltag(mp3tag);//copy base tags
    if (tg.title.isEmpty() || tg.title.isNull())
    {
        QFileInfo finfo(fname);
        tg.title = finfo.fileName();
    }
    tg.fname = fname;
    tgs_lst.append(tg);
    item->setText(tg.title);
    qDebug("plst:: add_fileqs end");
}

void plst::add_files(QStringList *lst)
{
    qDebug("plst:: add_files");
    if (lst->count() != 0)
        for (int i = 0; i < lst->count(); i++)
            add_fileqs(lst->at(i));
    qDebug("plst:: add_files end");
}

//--------------------------------------SLOTS---------------------------------------------
void plst::slot_file_add(void)
{
	qDebug("plst:: slot_file_add");
    QStringList *filenames = new QStringList;
    *filenames = QFileDialog::getOpenFileNames(this, tr("Open Audio File"), tr("/home"), tr("Audio Files (*.mp3 *.ogg *.wav *.mp2)"));
    QDesktopServices::storageLocation(QDesktopServices::MusicLocation);
    if (filenames->count() != 0)
        this->add_files(filenames);
   this->activateWindow();
    qDebug("plst:: slot_file_add end");
   delete filenames;
}


void plst::slot_file_open(void)
{
	qDebug("plst:: slot_file_open");
    this->clear();
    this->slot_file_add();
    qDebug("plst:: slot_file_open end");
}

#ifdef WIN32
const char slash = '\\';
#else
const char slash = '/';
#endif

void plst::slot_dir_add(void)
{
	qDebug("plst:: slot_dir_add");
    QString path = QFileDialog::getExistingDirectory(this, tr("Open Directory"), "/home",
                                                     QFileDialog::ShowDirsOnly
                                                     | QFileDialog::DontResolveSymlinks);
    if (path.isNull()) return;
    QDir dir(path);
    if (dir.exists())
    {
        QStringList lst = dir.entryList(QStringList() << "*.mp3"  << "*.ogg" << "*.wav" << "*.mp2", QDir::Files);
        for (int i = 0; i < lst.count(); i++)
            lst[i] = path + slash + lst[i];
        this->add_files(&lst);
    }
    this->show();
    qDebug("plst:: slot_dir_add end");
}

void plst::slot_dir_open(void)
{
	qDebug("plst:: slot_dir_open");
    this->clear();
    this->slot_dir_add();
    qDebug("plst:: slot_dir_open end");
}

bool check_unicode(QString &s)
{
    if (s.isEmpty() || s.isNull())
        return false;
    return (s[s.length() - 1] == '8');
}

void plst::slot_playlist_add(void)
{
	qDebug("plst:: slot_playlist_add");
    QString filename = QFileDialog::getOpenFileName(this, tr("Open Playlist"), tr("/"), tr("Playlist files (*.m3u *.m3u8)"));
    if (!filename.isNull())
    {
        QFile in(filename);
        if (!in.open(QIODevice::ReadOnly | QIODevice::Text))
        {
            QMessageBox::information(NULL, "ERROR", in.errorString());
            return;
        }
        while (!in.atEnd())
        {
            QString str;
            bs = in.readLine();
            if (check_unicode(filename))
                str = QString::fromUtf8(bs);
            else
                str = QString::fromLocal8Bit(bs);
            str = str.trimmed();
            if (str[0] != '#')
                add_fileqs(str);
        }
        in.close();
    }
    this->show();
    qDebug("plst:: slot_playlist_add end");
}

void plst::slot_playlist_open(void)
{
	qDebug("plst:: slot_playlist_open");
    this->clear();
    slot_playlist_add();
    qDebug("plst:: slot_playlist_open end");
}

void plst::slot_playlist_save(void)
{
	qDebug("plst:: slot_playlist_save");
   QString filename = QFileDialog::getSaveFileName(this, tr("Save Playlist"), tr("/"), tr("Playlist files (*.m3u *.m3u8)"));
   if (!filename.isNull())
   {
       QFile out(filename);
       if (!out.open(QIODevice::WriteOnly | QIODevice::Text))
       {
           QMessageBox::information(NULL, "ERROR", out.errorString());
           return;
       }
       for (int i = 0; i < tgs_lst.size(); i++)
       {
           QString str = tgs_lst[i].fname;
           QByteArray s1 = str.toUtf8();
           out.write(s1);
           out.write("\n");
       }
       out.close();
   }
   qDebug("plst:: slot_playlist_save end");
}
///----------------------ADDITIONAL PROCEDURES-----------IMPLEMENTATION


QString char2qs(TagLib::String str)
{
	qDebug("plst:: char2qs");
    QString res;
    res = str.toCString(true);
    qDebug("plst:: char2qs end");
    return res;
}

void *xmalloc(size_t size)
{
    void *res = malloc(size);
    if (!res)
        abort();
    return res;
}

char *tstring2char(TagLib::String str)
{
	qDebug("plst:: tstring2char");
    char *res = NULL;
    if ((!str.isEmpty()) && (!str.isNull()))
    {
        //res = (char *)xmalloc(sizeof(char) * str.size());
        res = new char[str.size() + 2];
        strcpy(res, str.toCString(true));
    }
    qDebug("plst:: tstring2char end");
    return res;
}

char *plst::QString2char(QString str)//copied slow
{
	qDebug("plst:: QString2char");
    char *res = NULL;
    if ((!str.isEmpty()) && (!str.isNull()))
    {
        res = new char [str.size()];
        strcpy(res, qs2char(str));
    }

    qDebug("plst:: QString2char end ");
    return res;
}

pl_tag id3v2_to_pltag(TagLib::ID3v2::Tag *tg)
{
	qDebug("plst:: id3v2_to_pltag");
    pl_tag res;
    if (tg != NULL)
    {
        res.album = tstring2char(tg->album());
        res.artist = tstring2char(tg->artist());
        res.title = tstring2char(tg->title());
        res.comment = tstring2char(tg->comment());
        res.genre = tstring2char(tg->genre());
        res.trackno = tg->track();
    }
    qDebug("plst:: id3v2_to_pltag end ");
    return res;
}
